﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.TeamFoundation.Build.Workflow.Activities;

namespace TfsBuildLauncher.Tests
{
    [TestClass]
    public class ProgramTests
    {
        [TestMethod]
        public void ParseParameters_SingleParam_ReturnsCorrectValue()
        {
            var result = Program.ParseParameters(new List<string> { "aa=bow" });

            Assert.AreEqual(1, result.Keys.Count, "Should have found 1 and only 1 parameter");
            Assert.IsTrue(result.ContainsKey("aa"), "There should be a \"aa\" key");
            Assert.AreEqual("bow", result["aa"], "The found value is incorrect");
        }

        [TestMethod]
        public void ParseParameters_BadlyFormattedArgument_ThrowsException()
        {
            try
            {
                var result = Program.ParseParameters(new List<string> { "there is no equal character here, it just cannot work" });
                Assert.Fail("Should have thrown an ArgumentException");
            }
            catch (ArgumentException ex)
            {
                Assert.IsTrue(ex.Message.Contains("there is no equal character here, it just cannot work"), "Exception message should contain the invalid argument's value"); ;
            }
        }

        [TestMethod]
        public void ParseParameters_NoArgument_Works()
        {
            var result = Program.ParseParameters(new List<string> { });
            Assert.AreEqual(0, result.Keys.Count, "Result should be an empty dictionary");
        }

        [TestMethod]
        public void ParseParameters_MissingParameterName_ThrowsException()
        {
            try
            {
                var result = Program.ParseParameters(new List<string> { "=nale" });
                Assert.Fail("Should have thrown an ArgumentException");
            }
            catch (ArgumentException ex)
            {
                Assert.IsTrue(ex.Message.Contains("=nale"), "Exception message should contain the invalid argument's value"); ;
            }
        }

        [TestMethod]
        public void ParseParameters_MissingParameterValue_SetsValueToNull()
        {
            var result = Program.ParseParameters(new List<string> { "paramName=" });
            Assert.IsTrue(result.ContainsKey("paramName"), "The parameter should be found in the list");
            Assert.IsNull(result["paramName"], "The value should be null");
        }

        [TestMethod]
        public void ParseParameters_BooleanParameterType_ReturnsCorrectValue()
        {
            var result = Program.ParseParameters(new List<string> { "RunAnalysis(System.Boolean)=true" });
            Assert.IsTrue(result.ContainsKey("RunAnalysis"), "The parameter should be found in the list");
            Assert.AreEqual(typeof(bool), result["RunAnalysis"].GetType(), "The value should be a boolean");
            Assert.AreEqual(true, result["RunAnalysis"], "Wrong value in the boolean");
        }

        [TestMethod]
        public void ParseParameters_BooleanWithoutNamespace_ReturnsCorrectValue()
        {
            var result = Program.ParseParameters(new List<string> { "RunAnalysis(Boolean)=true" });
            Assert.IsTrue(result.ContainsKey("RunAnalysis"), "The parameter should be found in the list");
            Assert.AreEqual(typeof(bool), result["RunAnalysis"].GetType(), "The value should be a boolean");
            Assert.AreEqual(true, result["RunAnalysis"], "Wrong value in the boolean");
        }

        
        [TestMethod]
        public void ParseParameters_IntParameterType_ReturnsCorrectValue()
        {
            var result = Program.ParseParameters(new List<string> { "MyGrandMothersAge(System.Int32)=48291" });
            Assert.IsTrue(result.ContainsKey("MyGrandMothersAge"), "The parameter should be found in the list");
            Assert.AreEqual(typeof(Int32), result["MyGrandMothersAge"].GetType(), "The value should be an Int32");
            Assert.AreEqual(48291, result["MyGrandMothersAge"], "Wrong value in the boolean");
        }

        [TestMethod]
        public void ParseParameters_StringList_ReturnsCorrectValue()
        {
            var resultParameters = Program.ParseParameters(new List<string> { "TheTags(StringList)=651,Mother,Nar Kadaal" });
            Assert.IsTrue(resultParameters.ContainsKey("TheTags"), "The parameter should be found in the list");
            Assert.AreEqual(typeof(StringList), resultParameters["TheTags"].GetType(), "The value should be a StringList");
            StringList result = (StringList)resultParameters["TheTags"];
            StringList expected = new StringList { "651", "Mother", "Nar Kadaal" };
            Assert.AreEqual(expected.Count, result.Count, "The stringlists must have the same number of elements");
            for (int i = 0; i < expected.Count;i++) Assert.AreEqual(expected[i], result[i], "The value " + i + " should be " + expected[i]);
        }

        [TestMethod]
        public void ParseParameters_StringArray_ReturnsCorrectValue()
        {
            var resultParameters = Program.ParseParameters(new List<string> { "MyArray(System.String[])=FirstVal,Mother 3,Nar Huumaan" });
            Assert.IsTrue(resultParameters.ContainsKey("MyArray"), "The parameter should be found in the list");
            Assert.AreEqual(typeof(String[]), resultParameters["MyArray"].GetType(), "The value should be a String[]");
            String[] result = (String[])resultParameters["MyArray"];
            String[] expected = new String[] { "FirstVal", "Mother 3", "Nar Huumaan" };
            Assert.AreEqual(expected.Length, result.Length, "The arrays must have the same number of elements");
            for (int i = 0; i < expected.Length; i++) Assert.AreEqual(expected[i], result[i], "The value " + i + " should be " + expected[i]);
        }

        [TestMethod]
        public void FindType_EnumWithoutNamespace_Works()
        {
            Type t = Program.FindType("BuildVerbosity");
            Assert.AreEqual<Type>(typeof(Microsoft.TeamFoundation.Build.Workflow.BuildVerbosity), t, "Should have found the Microsoft.TeamFoundation.Build.Workflow.BuildVerbosity Type");
        }

        [TestMethod]
        public void FindType_BooleanWithoutNamespace_FindsBool()
        {
            Type t = Program.FindType("Boolean");
            Assert.AreEqual<Type>(typeof(bool), t, "Should have found the boolean Type");
        }

        [TestMethod]
        public void FindType_StringArray_FindsStringArray()
        {
            Type t = Program.FindType("System.String[]");
            Assert.AreEqual<Type>(typeof(String[]), t, "Should have found the String array Type");
        }
    }
}
